home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 10
/
The PC-Sig Library - Shareware for the IBM PC and Compatibles (PC-SIG)(Tenth Edition Disks 1-2804)(1991).iso
/
PC_SIGCD
/
22
/
4
/
DISK2247.ZIP
/
CBASE101.ZIP
/
BTREE101.ZIP
/
NDOPS.C
< prev
next >
Wrap
Text File
|
1990-06-20
|
30KB
|
1,175 lines
/* Copyright (c) 1989 Citadel */
/* All Rights Reserved */
/* #ident "@(#)ndops.c 1.4 - 90/06/20" */
#include <blkio.h>
#include <bool.h>
#include <errno.h>
/*#include <stdlib.h>*/
/*#include <string.h>*/
/* local headers */
#include "btree_.h"
/*man---------------------------------------------------------------------------
NAME
bt_ndalloc - allocate memory for node
SYNOPSIS
#include "btree_.h"
btnode_t *bt_ndalloc(btp)
btree_t *btp;
DESCRIPTION
The bt_ndalloc function allocates an initialized in-core node for
btree btp. The address of the node created is returned.
bt_ndalloc will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[ENOMEM] Not enough memory is available for allocation by
the calling process.
[BTENOPEN] btp is not open.
SEE ALSO
bt_ndfree, bt_ndinit.
DIAGNOSTICS
On failure, a NULL pointer is returned, and errno set to indicate
the error.
------------------------------------------------------------------------------*/
btnode_t *bt_ndalloc(btp)
btree_t *btp;
{
btnode_t *btnp = NULL;
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp)) {
BTEPRINT;
errno = EINVAL;
return NULL;
}
/* check if not open */
if (!(btp->flags & BTOPEN)) {
BTEPRINT;
errno = BTENOPEN;
return NULL;
}
#endif
/* allocate storage for main node structure */
/* (calloc is used throughout to automatically set all bits 0) */
btnp = (btnode_t *)calloc((size_t)1, sizeof(btnode_t));
if (btnp == NULL) {
BTEPRINT;
errno = ENOMEM;
return NULL;
}
btnp->lsib = NIL;
btnp->rsib = NIL;
btnp->n = 0;
/* key array [1..m] (extra slot is for overflow) */
btnp->keyv = calloc((size_t)btp->bthdr.m, btp->bthdr.keysize);
if (btnp->keyv == NULL) {
BTEPRINT;
free(btnp);
errno = ENOMEM;
return NULL;
}
/* child node file postion array [0..m] */
btnp->childv = (bpos_t *)calloc((size_t)(btp->bthdr.m + 1), sizeof(*btnp->childv));
if (btnp->childv == NULL) {
BTEPRINT;
free(btnp->keyv);
free(btnp);
errno = ENOMEM;
return NULL;
}
errno = 0;
return btnp;
}
/*man---------------------------------------------------------------------------
NAME
bt_ndcopy - copy btree node
SYNOPSIS
#include "btree_.h"
int bt_ndcopy(btp, tbtnp, sbtnp)
btree_t *btp;
btnode_t *tbtnp;
const btnode_t *sbtnp;
DESCRIPTION
The bt_ndcopy function makes an exact copy of the in-core node
pointed to by sbtnp to the in-core node pointed to by tbtnp.
bt_ndcopy will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[EINVAL] tbtnp or sbtnp is the NULL pointer.
DIAGNOSTICS
Upon successful completion, a value of 0 is returned. Otherwise,
a value of -1 is returned, and errno set to indicate the error.
------------------------------------------------------------------------------*/
int bt_ndcopy(btp, tbtnp, sbtnp)
btree_t *btp;
btnode_t *tbtnp;
const btnode_t *sbtnp;
{
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp) || tbtnp == NULL || sbtnp == NULL) {
BTEPRINT;
errno = EINVAL;
return -1;
}
#endif
/* copy node sbtnp into tbtnp */
tbtnp->lsib = sbtnp->lsib;
tbtnp->rsib = sbtnp->rsib;
tbtnp->n = sbtnp->n;
memcpy(bt_kykeyp(btp, tbtnp, 1), bt_kykeyp(btp, sbtnp, 1), (size_t)(btp->bthdr.m * btp->bthdr.keysize));
memcpy(bt_kychildp(tbtnp, 0), bt_kychildp(sbtnp, 0), (size_t)((btp->bthdr.m + 1) * sizeof(*bt_kychildp(tbtnp, 0))));
errno = 0;
return 0;
}
/*man---------------------------------------------------------------------------
NAME
bt_nddelkey - delete key from btree node
SYNOPSIS
#include "btree_.h"
int bt_nddelkey(btp, btnp, kn)
btree_t *btp;
btnode_t *btnp;
int kn;
DESCRIPTION
The bt_nddelkey function deletes the tuple kn from the in-core
node pointed to by btnp.
bt_nddelkey will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[EINVAL] btnp is the NULL pointer.
SEE ALSO
bt_ndinskey, bt_ndsearch.
DIAGNOSTICS
Upon successful completion, a value of 0 is returned. Otherwise,
a value of -1 is returned, and errno set to indicate the error.
------------------------------------------------------------------------------*/
int bt_nddelkey(btp, btnp, kn)
btree_t *btp;
btnode_t *btnp;
int kn;
{
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp) || btnp == NULL) {
BTEPRINT;
errno = EINVAL;
return -1;
}
#endif
/* delete key kn */
if (bt_kyshift(btp, btnp, kn + 1, -1) == -1) {
BTEPRINT;
return -1;
}
errno = 0;
return 0;
}
/*man---------------------------------------------------------------------------
NAME
bt_ndfree - free in-core node
SYNOPSIS
#include "btree_.h"
void bt_ndfree(btnp)
btnode_t *btnp;
DESCRIPTION
The bt_ndfree function frees the in-core node pointed to by btnp.
SEE ALSO
bt_ndalloc.
------------------------------------------------------------------------------*/
void bt_ndfree(btnp)
btnode_t *btnp;
{
if (btnp == NULL) {
return;
}
if (btnp->keyv != NULL) free(btnp->keyv);
btnp->keyv = NULL;
if (btnp->childv != NULL) free(btnp->childv);
btnp->childv = NULL;
free(btnp);
return;
}
/*man---------------------------------------------------------------------------
NAME
bt_ndfuse - btree node fuse
SYNOPSIS
#include "btree_.h"
int bt_ndfuse(btp, lbtnp, rbtnp, pbtnp, pkn)
btree_t *btp;
btnode_t *lbtnp;
btnode_t *rbtnp;
btnode_t *pbtnp;
int pkn;
DESCRIPTION
The bt_ndfuse function fuses two nodes. lbtnp and rbtnp point to
in-core copies of nodes to be fused, the left and right sibling,
respectively. pbtnp points to an in-core copy of the parent
node. pkn is the number of the key in pbtnp whose left child is
lbtnp and right child is rbtnp.
On return, lbtnp contains the fused node and rbtnp is empty.
Both the left and right nodes are written to the file. pbtnp is
modified during the fusion, but is not written to the file; the
calling program must write pbtnp to the file.
bt_ndfuse will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[EINVAL] btnp, rbtnp, or pbtnp is NULL.
[EINVAL] pkn is less than 1 or greater than pbtnp->n.
[BTENOPEN] btp is not open.
[BTEPANIC] The total number of keys in lbtnp and rbtnp is
too large to fuse into one node.
SEE ALSO
bt_ndshift, bt_ndsplit.
DIAGNOSTICS
Upon successful completion, a value of 0 is returned. Otherwise,
a value of -1 is returned, and errno set to indicate the error.
------------------------------------------------------------------------------*/
int bt_ndfuse(btp, lbtnp, rbtnp, pbtnp, pkn)
btree_t *btp;
btnode_t *lbtnp;
btnode_t *rbtnp;
btnode_t *pbtnp;
int pkn;
{
bttpl_t bttpl; /* (key, child address) tuple */
bool leaf = FALSE; /* leaf node flag */
bpos_t lnode = 0; /* left node block number */
bpos_t rnode = 0; /* right node block number */
/* initialize automatic aggregates */
memset(&bttpl, 0, sizeof(bttpl));
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp)) {
BTEPRINT;
errno = EINVAL;
return NULL;
}
if (lbtnp == NULL || rbtnp == NULL || pbtnp == NUL) {
BTEPRINT;
errno = EINVAL;
return -1;
}
if (pkn < 1 || pkn > pbtnp->n) {
BTEPRINT;
errno = EINVAL;
return -1;
}
/* check if too many keys for fusion */
if (lbtnp->n + rbtnp->n > bt_ndmax(btp) - (leaf ? 0 : 1)) {
BTEPRINT;
errno = BTEPANIC;
return -1;
}
#endif
/* check if leaf */
if (bt_ndleaf(lbtnp)) {
leaf = TRUE;
}
/* get block number of sibling nodes */
lnode = rbtnp->lsib;
rnode = lbtnp->rsib;
/* if internal node, bring down parent key pkn */
if (!leaf) {
bttpl.keyp = calloc((size_t)1, btp->bthdr.keysize);
if (bttpl.keyp == NULL) {
BTEPRINT;
errno = ENOMEM;
return -1;
}
if (bt_kyread(btp, pbtnp, pkn, &bttpl) == -1) {
BTEPRINT;
free(bttpl.keyp);
return -1;
}
bttpl.child = *bt_kychildp(rbtnp, 0);
if (bt_ndinskey(btp, lbtnp, lbtnp->n + 1, &bttpl) == -1) {
BTEPRINT;
free(bttpl.keyp);
return -1;
}
free(bttpl.keyp);
bttpl.keyp = NULL;
}
/* move keys from rbtnp to lbtnp */
if (bt_kymvleft(btp, lbtnp, rbtnp, rbtnp->n) == -1) {
BTEPRINT;
return -1;
}
/* return right node to free list */
if (bflpush(btp->bp, &rnode) == -1) {
BTEPRINT;
return -1;
}
/* fix sibling links */ /*L=left N=new right */
lbtnp->rsib = rbtnp->rsib; /* L -> N */
if (lbtnp->rsib == NIL) { /* L <- N */
if (leaf) btp->bthdr.last = lnode;
} else {
if (bputbf(btp->bp, lbtnp->rsib, offsetof(btnode_t, lsib), &lnode, sizeof(lbtnp->lsib)) == -1) {
BTEPRINT;
return -1;
}
}
/* initialize in-core copy of right sibling */
bt_ndinit(btp, rbtnp);
/* delete parent key of right sibling */
if (bt_nddelkey(btp, pbtnp, pkn) == -1) {
BTEPRINT;
return -1;
}
/* write fused node */
if (bt_ndput(btp, lnode, lbtnp) == -1) {
BTEPRINT;
return -1;
}
errno = 0;
return 0;
}
/*man---------------------------------------------------------------------------
NAME
bt_ndget - get btree node from file
SYNOPSIS
#include "btree_.h"
int bt_ndget(btp, node, btnp)
btree_t *btp;
bpos_t node;
btnode_t *btnp;
DESCRIPTION
The bt_ndget function reads the contents of a node into the
in-core node pointed to by btnp to the file. node is the block
number of the node in the file.
bt_ndget will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[EINVAL] btnp is NULL.
[EINVAL] node is NIL.
[EINVAL] btnp is NULL.
[BTENOPEN] btp is not open.
SEE ALSO
bt_ndput.
DIAGNOSTICS
Upon successful completion, a value of 0 is returned. Otherwise,
a value of -1 is returned, and errno set to indicate the error.
------------------------------------------------------------------------------*/
int bt_ndget(btp, node, btnp)
btree_t *btp;
bpos_t node;
btnode_t *btnp;
{
void *buf = NULL;
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp) || node == NIL || btnp == NULL) {
BTEPRINT;
errno = EINVAL;
return -1;
}
/* check if not open */
if (!(btp->flags & BTOPEN)) {
BTEPRINT;
errno = BTENOPEN;
return -1;
}
#endif
/* read node from file */
buf = calloc((size_t)1, bt_blksize(btp));
if (buf == NULL) {
BTEPRINT;
errno = ENOMEM;
return -1;
}
if (bgetb(btp->bp, node, buf) == -1) {
BTEPRINT;
free(buf);
return -1;
}
/* convert file node to in-core format */
memcpy(btnp, buf, offsetof(btnode_t, keyv));
memcpy(btnp->keyv,
((char *)buf + offsetof(btnode_t, keyv)),
((btp->bthdr.m - 1) * btp->bthdr.keysize));
memcpy(btnp->childv,
((char *)buf + offsetof(btnode_t, keyv) +
((btp->bthdr.m - 1) * btp->bthdr.keysize)),
(btp->bthdr.m * sizeof(*btnp->childv)));
/* free buffer */
free(buf);
errno = 0;
return 0;
}
/*man---------------------------------------------------------------------------
NAME
bt_ndinit - initialize in-core node
SYNOPSIS
#include "btree_.h"
void bt_ndinit(btp, btnp)
btree_t *btp;
btnode_t *btnp;
DESCRIPTION
The bt_ndinit function initializes the in-core node btnp.
------------------------------------------------------------------------------*/
void bt_ndinit(btp, btnp)
btree_t *btp;
btnode_t *btnp;
{
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp) || btnp == NULL) {
BTEPRINT;
errno = EINVAL;
return;
}
#endif
/* initialize btnp */
btnp->lsib = NIL;
btnp->rsib = NIL;
btnp->n = 0;
memset(btnp->keyv, 0, (size_t)(btp->bthdr.m * btp->bthdr.keysize));
memset(btnp->childv, 0, (size_t)((btp->bthdr.m + 1) * sizeof(*btnp->childv)));
return;
}
/*man---------------------------------------------------------------------------
NAME
bt_ndinskey - insert key into btree node
SYNOPSIS
#include "btree_.h"
int bt_ndinskey(btp, btnp, kn, bttplp)
btree_t *btp;
btnode_t *btnp;
int kn;
const bttpl_t *bttplp;
DESCRIPTION
The bt_ndinskey function inserts bttplp into the knth slot in
the in-core btree node btnp. The node is not written to the
file.
bt_ndinskey will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[EINVAL] btnp is the NULL pointer.
[EINVAL] kn is less than 1 or greater than the number of
keys in btnp plus 1.
SEE ALSO
bt_nddelkey, bt_ndsearch.
DIAGNOSTICS
Upon successful completion, a value of 0 is returned. Otherwise,
a value of -1 is returned, and errno set to indicate the error.
------------------------------------------------------------------------------*/
int bt_ndinskey(btp, btnp, kn, bttplp)
btree_t *btp;
btnode_t *btnp;
int kn;
const bttpl_t *bttplp;
{
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp) || btnp == NULL || bttplp == NULL) {
BTEPRINT;
errno = EINVAL;
return -1;
}
if (kn < 1 || kn > btnp->n + 1) {
BTEPRINT;
errno = EINVAL;
return -1;
}
/* check if room to insert */
if (btnp->n >= btp->bthdr.m) {
BTEPRINT;
errno = BTEPANIC;
return -1;
}
#endif
/* make an empty slot */
if (bt_kyshift(btp, btnp, kn, 1) == -1) {
BTEPRINT;
return -1;
}
/* put new key into empty slot */
if (bt_kywrite(btp, btnp, kn, bttplp) == -1) {
BTEPRINT;
return -1;
}
errno = 0;
return 0;
}
/*man---------------------------------------------------------------------------
NAME
bt_ndleaf - is btree node leaf
SYNOPSIS
#include "btree_.h"
int bt_ndleaf(btnp)
btnode_t *btnp;
DESCRIPTION
bt_ndleaf returns a true value if btnp is a leaf node or a false
value if it is not. If btnp does not point to a valid in-core
btree node, the results are undefined. bt_ndleaf is a macro.
SEE ALSO
bt_ndmax, bt_ndmin.
------------------------------------------------------------------------------*/
/* bt_ndleaf is defined in btree_.h. */
/*man---------------------------------------------------------------------------
NAME
bt_ndmax - maximum keys per node
SYNOPSIS
#include "btree_.h"
int bt_ndmax(btp)
btree_t *btp;
DESCRIPTION
bt_ndmin returns the maximum number of keys allowable in a node
of btree btp. If btp does not point to a valid open btree, the
results are undefined. bt_ndmax is a macro.
SEE ALSO
bt_ndleaf, bt_ndmin.
------------------------------------------------------------------------------*/
/* bt_ndmax is defined in btree_.h. */
/*man---------------------------------------------------------------------------
NAME
bt_ndmin - minimum keys per node
SYNOPSIS
#include "btree_.h"
int bt_ndmin(btp)
btree_t *btp;
DESCRIPTION
bt_ndmin returns the minimum number of keys allowable in a node
of btree btp. If btp does not point to a valid open btree, the
results are undefined. bt_ndmin is a macro.
SEE ALSO
bt_ndleaf, bt_ndmax.
------------------------------------------------------------------------------*/
/* bt_ndmin is defined in btree_.h. */
/*man---------------------------------------------------------------------------
NAME
bt_ndput - put btree node to file
SYNOPSIS
#include "btree_.h"
int bt_ndput(btp, node, btnp)
btree_t *btp;
bpos_t node;
const btnode_t *btnp;
DESCRIPTION
The bt_ndput function writes the contents of the in-core node
pointed to by btnp to the file. node is the block number of the
node in the file.
bt_ndput will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[EINVAL] btnp is NULL.
[EINVAL] node is NIL.
[EINVAL] btnp is NULL.
[BTENOPEN] btp is not open.
SEE ALSO
bt_ndget.
DIAGNOSTICS
Upon successful completion, a value of 0 is returned. Otherwise,
a value of -1 is returned, and errno set to indicate the error.
------------------------------------------------------------------------------*/
int bt_ndput(btp, node, btnp)
btree_t *btp;
bpos_t node;
const btnode_t *btnp;
{
void *buf = NULL;
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp) || node == NIL || btnp == NULL) {
BTEPRINT;
errno = EINVAL;
return -1;
}
/* check if not open */
if (!(btp->flags & BTOPEN)) {
BTEPRINT;
errno = BTENOPEN;
return -1;
}
#endif
/* convert in-core node to file format */
buf = calloc((size_t)1, bt_blksize(btp));
if (buf == NULL) {
BTEPRINT;
errno = ENOMEM;
return -1;
}
memcpy(buf, btnp, offsetof(btnode_t, keyv));
memcpy(((char *)buf + offsetof(btnode_t, keyv)),
btnp->keyv,
((btp->bthdr.m - 1) * btp->bthdr.keysize));
memcpy(((char *)buf + offsetof(btnode_t, keyv) +
((btp->bthdr.m - 1) * btp->bthdr.keysize)),
btnp->childv,
(btp->bthdr.m * sizeof(*btnp->childv)));
/* write node to file */
if (bputb(btp->bp, node, buf) == -1) {
BTEPRINT;
free(buf);
return -1;
}
/* free buffer */
free(buf);
errno = 0;
return 0;
}
/*man---------------------------------------------------------------------------
NAME
bt_ndsearch - search btree node
SYNOPSIS
#include "btree_.h"
int bt_ndsearch(btp, btnp, buf, knp)
btree_t *btp;
const btnode_t *btnp;
const void *buf;
int *knp;
DESCRIPTION
Function searches the in-core node btnp for the key pointed to by
buf. On return, the location of the smallest key >= that pointed
to by buf is in the location pointed to by knp.
bt_ndsearch will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[EINVAL] btnp is NULL.
[EINVAL] buf is NULL.
[EINVAL] knp is NULL.
SEE ALSO
bt_nddelkey, bt_ndinskey.
DIAGNOSTICS
Upon successful completion, a value of 0 is returned if the key
was found or a value of 1 is it was not found. Otherwise, a
value of -1 is returned, and errno set to indicate the error.
------------------------------------------------------------------------------*/
int bt_ndsearch(btp, btnp, buf, knp)
btree_t *btp;
const btnode_t *btnp;
const void *buf;
int *knp;
{
int cmp = 0; /* result of key comparison */
int fld = 0; /* field number */
bool found = FALSE; /* key found flag */
int kn = 0; /* key number */
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp) || btnp == NULL || buf == NULL || knp == NULL) {
BTEPRINT;
errno = EINVAL;
return -1;
}
#endif
/* initialize */
*knp = 0;
/* locate key */
for (kn = 1; kn <= btnp->n; ++kn) {
for (fld = 0; fld < btp->fldc; ++fld) {
cmp = (*btp->fldv[fld].cmp)(bt_kykfp(btp, btnp, kn, fld),
(char *)buf + btp->fldv[fld].offset,
btp->fldv[fld].len);
if (cmp != 0) {
break;
}
}
if (cmp == 0) {
found = TRUE;
break;
}
if (btp->fldv[fld].flags & BT_FDSC) {
if (cmp < 0) break; /* descending order */
} else {
if (cmp > 0) break; /* ascending order */
}
}
*knp = kn;
errno = 0;
return (found ? 1 : 0);
}
/*man---------------------------------------------------------------------------
NAME
bt_ndshift - node shift
SYNOPSIS
#include "btree_.h"
int bt_ndshift(btp, lbtnp, rbtnp, pbtnp, pkn, pnode)
btree_t *btp;
btnode_t *lbtnp;
btnode_t *rbtnp;
btnode_t *pbtnp;
int pkn;
bpos_t pnode;
DESCRIPTION
The bt_ndshift function shifts keys between two sibling nodes to
give them both the same number of keys (+/- 1). lbtnp and rbtnp
are in-core copies of the two siblings. pbtnp is an in-core copy
of the parent node of the two siblings. pkn is the number of the
key in pbtnp whose left child is lbtnp and right child is rbtnp.
The left, right, and parent nodes are written to the file.
bt_ndshift will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[EINVAL] lbtnp, rbtnp, or pbtnp is NULL.
[EINVAL] pkn is less than 1 or greater than pbtnp->n.
[BTENOPEN] btp is not open.
[BTEPANIC] Not enough keys in lbtnp and rbtnp to achieve
the minimum number in both nodes.
SEE ALSO
bt_ndfuse, bt_ndsplit.
DIAGNOSTICS
Upon successful completion, a value of 0 is returned. Otherwise,
a value of -1 is returned, and errno set to indicate the error.
------------------------------------------------------------------------------*/
int bt_ndshift(btp, lbtnp, rbtnp, pbtnp, pkn, pnode)
btree_t *btp;
btnode_t *lbtnp;
btnode_t *rbtnp;
btnode_t *pbtnp;
int pkn;
bpos_t pnode;
{
bttpl_t bttpl; /* (key, child address) tuple */
bool leaf = FALSE; /* leaf node flag */
bool right = FALSE; /* shift direction flag */
int ns = 0; /* number keys to shift */
/* initialize automatic aggregates */
memset(&bttpl, 0, sizeof(bttpl));
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp)) {
BTEPRINT;
errno = EINVAL;
return NULL;
}
if (lbtnp == NULL || rbtnp == NULL || pbtnp == NULL) {
BTEPRINT;
errno = EINVAL;
return -1;
}
if (pkn < 1 || pkn > pbtnp->n) {
BTEPRINT;
errno = EINVAL;
return -1;
}
/* check if not open */
if (!(btp->flags & BTOPEN)) {
BTEPRINT;
errno = BTENOPEN;
return NULL;
}
/* check if enough keys to shift */
if (lbtnp->n + rbtnp->n < 2 * bt_ndmin(btp)) {
errno = BTEPANIC;
return -1;
}
/* check if too many keys to shift */
if (lbtnp->n + rbtnp->n > 2 * bt_ndmax(btp)) {
errno = BTEPANIC;
return -1;
}
#endif
/*printf("IN NDSHIFT: pkn = %d, pnode = %lu.\n", pkn, pnode);*/
/* set leaf and direction flags */
if (bt_ndleaf(lbtnp)) {
leaf = TRUE;
}
if (lbtnp->n > rbtnp->n) {
right = TRUE;
} else {
right = FALSE;
}
/* if internal node, bring down parent key pkn */
if (!leaf) {
bttpl.keyp = calloc((size_t)1, btp->bthdr.keysize);
if (bttpl.keyp == NULL) {
BTEPRINT;
errno = ENOMEM;
return -1;
}
if (bt_kyread(btp, pbtnp, pkn, &bttpl) == -1) {
BTEPRINT;
free(bttpl.keyp);
return -1;
}
bttpl.child = *bt_kychildp(rbtnp, 0);
if (right) {
if (bt_ndinskey(btp, rbtnp, 1, &bttpl) == -1) {
BTEPRINT;
free(bttpl.keyp);
return -1;
}
*bt_kychildp(rbtnp, 0) = *bt_kychildp(lbtnp, lbtnp->n);
} else {
if (bt_ndinskey(btp, lbtnp, lbtnp->n + 1, &bttpl) == -1) {
BTEPRINT;
free(bttpl.keyp);
return -1;
}
*bt_kychildp(lbtnp, lbtnp->n) = *bt_kychildp(rbtnp, 0);
}
free(bttpl.keyp);
bttpl.keyp = NULL;
}
/* calculate number of keys to shift (+ -> shift to right) */
ns = (lbtnp->n - rbtnp->n) / 2;
if (ns < 0) ns = -ns;
/*printf("NODES BEFORE SHIFT:\n");
puts("Left:");
bt_dgnode(btp, lbtnp, stdout);
puts("Right:");
bt_dgnode(btp, rbtnp, stdout);*/
/* shift keys */
if (right) {
if (bt_kymvright(btp, lbtnp, rbtnp, ns) == -1) {
BTEPRINT;
return -1;
}
} else {
if (bt_kymvleft(btp, lbtnp, rbtnp, ns) == -1) {
BTEPRINT;
return -1;
}
}
/*printf("NODES AFTER SHIFT BUT BEFORE EXTRACT PARENT KEY:\n");
puts("Left:");
bt_dgnode(btp, lbtnp, stdout);
puts("Right:");
bt_dgnode(btp, rbtnp, stdout);*/
/* bring up new parent key (child of pkn remains right node) */
if (!leaf) {
if (lbtnp->n > rbtnp->n) {
memcpy(bt_kykeyp(btp, pbtnp, pkn), bt_kykeyp(btp, lbtnp, lbtnp->n), btp->bthdr.keysize);
if (bt_nddelkey(btp, lbtnp, lbtnp->n) == -1) {
BTEPRINT;
return -1;
}
} else {
memcpy(bt_kykeyp(btp, pbtnp, pkn), bt_kykeyp(btp, rbtnp, 1), btp->bthdr.keysize);
*bt_kychildp(rbtnp, 0) = *bt_kychildp(rbtnp, 1);
if (bt_nddelkey(btp, rbtnp, 1) == -1) {
BTEPRINT;
return -1;
}
}
} else {
memcpy(bt_kykeyp(btp, pbtnp, pkn), bt_kykeyp(btp, rbtnp, 1), btp->bthdr.keysize);
}
/*printf("NODES AFTER EXTRACT PARENT KEY:\n");
puts("Left:");
bt_dgnode(btp, lbtnp, stdout);
puts("Right:");
bt_dgnode(btp, rbtnp, stdout);*/
/* write lbtnp, rbtnp, and pbtnp to file */
if (bt_ndput(btp, *bt_kychildp(pbtnp, pkn - 1), lbtnp) == -1) {
BTEPRINT;
return -1;
}
if (bt_ndput(btp, *bt_kychildp(pbtnp, pkn), rbtnp) == -1) {
BTEPRINT;
return -1;
}
if (bt_ndput(btp, pnode, pbtnp) == -1) {
BTEPRINT;
return -1;
}
errno = 0;
return 0;
}
/*man---------------------------------------------------------------------------
NAME
bt_ndsplit - btree node split
SYNOPSIS
#include "btree_.h"
int bt_ndsplit(btp, node, btnp, rbtnp, bttplp)
btree_t *btp;
bpos_t node;
btnode_t *btnp;
btnode_t *rbtnp;
bttpl_t *bttplp;
DESCRIPTION
The bt_ndsplit function splits a btree node. btnp points to an
in-core copy of the node to be split. node is the block number
of this node in the file. The splitting will produce a new right
sibling for this node. Both the modified and the new node are
written to the file. If btnp had a right sibling prior to the
split, the lsib link field in that node is updated, also.
On return, btnp and rbtnp contain copies of the split node and
its new right sibling, respectively, and the tuple pointed to by
bttplp contains the (key, child address) tuple to be inserted in
the parent of the split node; bttplp->child contains the block
number of the new right sibling node.
bt_ndsplit will fail if one or more of the following is true:
[EINVAL] btp is not a valid btree pointer.
[EINVAL] btnp, rbtnp, or bttplp is NULL.
[BTENOPEN] btp is not open.
[BTEPANIC] The number of keys in btnp is not equal to m.
SEE ALSO
bt_ndfuse, bt_ndshift.
DIAGNOSTICS
Upon successful completion, a value of 0 is returned. Otherwise,
a value of -1 is returned, and errno set to indicate the error.
------------------------------------------------------------------------------*/
int bt_ndsplit(btp, node, btnp, rbtnp, bttplp)
btree_t *btp;
bpos_t node;
btnode_t *btnp;
btnode_t *rbtnp;
bttpl_t *bttplp;
{
bool leaf = FALSE; /* leaf node flag */
int midkn = 0; /* middle key number */
bpos_t rnode = 0; /* right node block number */
int terrno = 0; /* tmp errno */
#ifdef DEBUG
/* validate arguments */
if (!bt_valid(btp)) {
BTEPRINT;
errno = EINVAL;
return NULL;
}
if (btnp == NULL || rbtnp == NULL || bttplp == NULL) {
BTEPRINT;
errno = EINVAL;
return -1;
}
/* check if not open */
if (!(btp->flags & BTOPEN)) {
BTEPRINT;
errno = BTENOPEN;
return NULL;
}
/* check if node not one over full */
if (btnp->n != bt_ndmax(btp) + 1) {
BTEPRINT;
errno = BTEPANIC;
return -1;
}
#endif
/* initialize */
bt_ndinit(btp, rbtnp);
/* check if leaf node */
if (bt_ndleaf(btnp)) {
leaf = TRUE;
}
/* get new block for right sibling node */
if (bflpop(btp->bp, &rnode) == -1) {
BTEPRINT;
return -1;
}
/* fix sibling links */ /*L=left R=right O=old right */
rbtnp->rsib = btnp->rsib; /* L R -> O */
btnp->rsib = rnode; /* L -> R O */
rbtnp->lsib = node; /* L <- R O */
if (rbtnp->rsib == NIL) { /* L R <- O */
if (leaf) btp->bthdr.last = rnode;
} else {
if (bputbf(btp->bp, rbtnp->rsib, offsetof(btnode_t, lsib),
&rnode, sizeof(rbtnp->lsib)) == -1) {
BTEPRINT;
terrno = errno;
bflpush(btp->bp, &rnode);
errno = terrno;
return -1;
}
}
/* calculate middle key number */
midkn = btnp->n / 2 + 1;
/* get middle (key, child) tuple into bttplp */
if (bt_kyread(btp, btnp, midkn, bttplp) == -1) {
BTEPRINT;
terrno = errno;
bflpush(btp->bp, &rnode);
errno = terrno;
return -1;
}
bttplp->child = rnode;
/* shift keys from left sibling */
if (leaf) {
/* move midkn thru n to right sibling */
if (bt_kymvright(btp, btnp, rbtnp, btnp->n - midkn + 1) == -1) {
BTEPRINT;
return -1;
}
} else {
/* move midkn + 1 thru n to right sibling */
if (bt_kymvright(btp, btnp, rbtnp, btnp->n - midkn) == -1) {
BTEPRINT;
return -1;
}
/* delete midkn */
if (bt_nddelkey(btp, btnp, midkn) == -1) {
BTEPRINT;
return -1;
}
}
/* write split nodes */
if (bt_ndput(btp, node, btnp) == -1) {
BTEPRINT;
return -1;
}
if (bt_ndput(btp, rnode, rbtnp) == -1) {
BTEPRINT;
return -1;
}
errno = 0;
return 0;
}